package main

import (
	"fmt"
	"math/rand"
)

func main() {
	//des1()
	//des2()
	//des3()
	//des4()
	//Test()
	//des5()
	//des7()
	//plan := []string{"Mars", "Uranus", "Neptune"}
	//var p planets
	//p.terraform(plan)
	//fmt.Println(plan)
	plan := []string{"Link", "V", "Geralt"}
	des10("Virgli", plan...)

}

type planets string

func des1() {
	//数组
	//数组是一种固定长度且有序的元素集合
	//定义一个数组：
	var planets [8]string
	fmt.Println(planets)
	//访问数组元素
	//和其他编程语言相同，通过[]+索引访问
	planets[0] = "Virgli"
	planets[1] = "Link"
	fmt.Println(planets)
	//数组长度可以由由内置函数打印
	a := len(planets)
	fmt.Println(a)
	//在数组声明后未被赋值的部分对应的类型是零值
	//使用复合字面值来初始化数组
	//复合字面值是一种给复合类型初始化的紧凑形语法，GO的复合字面值语法允许我们一步就完成数组的声明和数组的初始化两个操作
	list1 := [3]string{"Virgli", "Link", "V"}
	//可以在复合字面值中使用...作为数组的长度，这样Go编译器会给你算出数组的元素数量
	list2 := [...]string{"Virgli", "Link", "V", "Skior"}
	fmt.Println(list1, "\n", list2)
}

func des2() {
	//循环遍历数组
	names := [...]string{"Virgli", "Link", "Geralt", "V"}
	//1.通过for循环搭配索引直接遍历
	for i := 0; i < len(names); i++ {
		fmt.Println(names[i])
	}
	//2.使用range遍历
	//类似于java的foreach，返回此时的下标和对应的值
	for i, name := range names {
		fmt.Println(i, " ", name)
	}

}

func des3() {
	//数组的复制
	//无论数组赋值给新的变量还是将它传递给函数，都会产生一个新的完整的数组副本
	names := [...]string{"Virgli", "Link", "Geralt", "V"}
	name2 := names

	names[2] = "Zelda"
	fmt.Println(name2)
	fmt.Println(names)
	//数组也是一种值，函数通过值传递来接收参数。所以数组作为函数的参数效率就特别的低
	//数组的长度也是数组类型的一部分，不同长度的数组不是同一类型，不能相互传递
}

func des4() {
	//二维数组
	var twoDimArray [5][5]int8
	twoDimArray[0][1] = 8
	twoDimArray[3][4] = 6

	fmt.Println(twoDimArray)

}

func Test() {
	//设计一个9X9的数独表格
	var table [9][9]int
	for i := 0; i < 9; i++ {
		for j := 0; j < 9; j++ {
			table[i][j] = rand.Intn(10)
		}
	}

	fmt.Println(table)
}

func des5() {
	//切片Slice
	//切片就是指向数组的窗口/视图
	//切分数组不会导致数组被修改，它只是创建了指向数组的一个窗口或者视图，这种视图就是切片类型
	//假设array是一个数组，那么array[0：4]就是一个切片，它分出了数组的前四个元素0，1，2，3，切片是左闭右开[0,4)
	names := [...]string{
		"Virgli",
		"Link",
		"V",
		"Geralt",
		"Jack",
	}
	name := names[0:3]
	fmt.Println(name)
}

func des6() {
	//Slice的默认索引
	//如果忽略掉起始索引，表示从数组的起始位置进行切分
	//如果忽略掉结束索引，相当于以数组的长度作为结束索引
	//Go中Slice的索引不能为负数
	names := [...]string{
		"Virgli",
		"Link",
		"V",
		"Geralt",
		"Jack",
	}
	name1 := names[2:]
	name2 := names[:3]
	fmt.Println(name1)
	fmt.Println(name2)
}

func des7() {
	//Slice的复合字面值
	//Go里面很多函数都倾向于使用slice而不是数组作为参数，而将切片作为参数传递是，不需要考虑切片的长度
	//想要获得与底层数组相同元素的slice，那么可以直接使用[:]进行切分
	//切分数组并不是获取Slice的唯一方法，也可以自己定义Slice
	Slice := []string{
		"Virgli",
		"Link",
		"V",
		"Geralt",
		"Jack",
	}
	fmt.Println(Slice)
	fmt.Printf("%T", Slice)
	//本质还是先创建了一个数组，然后再利用数组进行切片，所创建的数组我们是不可见的
}

func (p planets) terraform(plane []string) {
	for i := range plane {
		plane[i] = "New" + plane[i]
	}
}

func des8() {
	//Slice添加数据
	//内置的append函数可以为Slice动态添加数据
	array := []string{"Virgli", "V", "Link"}
	fmt.Println(array)
	array = append(array, "Geralt")
	array = append(array, "Skrio", "Zelda")
	fmt.Println(array)
}

func des9() {
	//长度和容量
	//Slice中元素的个数决定了slice的长度
	//如果slice的底层数组比slice还大，那么就说该slice还有容量可以提供增长
	//可以使用len()来查看切片长度，cap()来查看切片容量

	//三索引的切分操作
	//可以通过第三个索引来确定切片的容量大小，前两个数字代表切的范围，最后一个代表切片容量
	names := [...]string{
		"Virgli",
		"Link",
		"V",
		"Geralt",
		"Jack",
	}
	name := names[0:2:3]
	fmt.Printf("len:%v;cap:%v", len(name), cap(name))

	//使用make函数对slice进行预分配
	//当slice的容量不足以执行append操作时，Go必须重新创建新的数组并复制旧的数组到其中
	//但通过内置的make函数，可以对slice进行预分配策略

}

// 声明可变参数的函数
// 在声明可变参数函数的时候，需要在函数的最后一个参数前面...

func des10(name string, friends ...string) {
	fmt.Printf("name:%v,friend:%v", name, friends)
}
